package com.libre.generator.util;

import com.libre.common.utils.StringUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.*;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @description 代码生成器
 * @author 庞留杰
 * @date 2020/7/28 13:04
 * @version V1.0
 **/
public class AutoGeneratorUtil {
    /* 数据库 */
    private String url;
    private String name;
    private String passWord;
    private String driver;
    private String sql;//查询语句
    private String tableName;//表名
    private String templateDir;//模板路径
    private String moduleName;//module名
    private String businessName;//业务名
    private String author;//作者
    private String description; //描述信息
    private String version; //版本
    private String[] packageName = new String[6];//包名
    private static String[][] fileNameArray = new String[6][2];

    static {
        //实体类
        fileNameArray[0][0] = "template.ftl";
        fileNameArray[0][1] = ".java";
        //mapper
        fileNameArray[1][0] = "mapperTemplate.ftl";
        fileNameArray[1][1] = "Mapper.java";
        //service
        fileNameArray[2][0] = "serviceTemplate.ftl";
        fileNameArray[2][1] = "Service.java";
        //serviceImpl
        fileNameArray[3][0] = "serviceImplTemplate.ftl";
        fileNameArray[3][1] = "ServiceImpl.java";
        //controller
        fileNameArray[4][0] = "controllerTemplate.ftl";
        fileNameArray[4][1] = "Controller.java";
        //Mapper.xml
        fileNameArray[5][0] = "mapperXmlTemplate.ftl";
        fileNameArray[5][1] = "Mapper.xml";//需要生成什么样的文件
    }

    public AutoGeneratorUtil(String url, String name, String passWord, String driver, String tableName,
                             String moduleName, String businessName, String author, String description, String version) {
        this.url = url;
        this.name = name;
        this.passWord = passWord;
        this.driver = driver;
        this.sql = "select t.COLUMN_NAME,t.COLUMN_TYPE,t.COLUMN_COMMENT from information_schema.columns t where t.table_name='" + tableName + "';";
        this.tableName = tableName;
        this.templateDir = System.getProperty("user.dir") + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + "com" + File.separator + "libre" + File.separator + "generator" + File.separator + "template";//模板路径
        this.moduleName = moduleName;
        this.businessName = businessName;//buss.entrust
        this.author = author;//作者
        this.description = description; //描述信息
        this.version = version; //描述信息
    }

    public void autoGenerationJavaCode() throws IOException, TemplateException, ClassNotFoundException,
            SQLException {
        Configuration cfg = new Configuration();
        cfg.setDefaultEncoding("utf-8");
        String className = dealTableName();//首字母小写的类名
        String fileName = dealClassName(className);
        //设置模板文件路径
        cfg.setDirectoryForTemplateLoading(new File(templateDir));
        Map<String, Object> rootMap = new HashMap<String, Object>();
        this.getConn(rootMap);
        //在map中存的值XXXX，在模板文件.ftl中，用${XXXX}取，即可
        rootMap.put("className", className); //首字母小写的类名
        rootMap.put("tableName", tableName);//表名
        // String str = moduleName.split("zksz-")[1];//sys
        String str = "";//sys
        str = str + "." + businessName;
        packageName[0] = "com.libre." + str + ".entity";
        packageName[1] = "com.libre." + str + ".mapper";
        packageName[2] = "com.libre." + str + ".service";
        packageName[3] = "com.libre." + str + ".service.impl";
        packageName[4] = "com.libre." + str + ".controller";
        rootMap.put("entityPackageName", packageName[0]);
        rootMap.put("mapperPackageName", packageName[1]);
        rootMap.put("servicePackageName", packageName[2]);
        rootMap.put("implPackageName", packageName[3]);
        rootMap.put("controllerPackageName", packageName[4]);
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        rootMap.put("createTime", format.format(new Date()));
        rootMap.put("version", version);
        rootMap.put("author", author);
        rootMap.put("description", description);
        //生成文件路径【使用：File.separator替换\\，处理跨平台问题】
        File[] fileArray = new File[6];
        fileArray[0] = new File(moduleName + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + "com" + File.separator + "libre" + File.separator + "" + str.replace(".", "//") + "" + File.separator + "entity");//entity
        fileArray[1] = new File(moduleName + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + "com" + File.separator + "libre" + File.separator + "" + str.replace(".", "//") + "" + File.separator + "mapper");//dao
        fileArray[2] = new File(moduleName + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + "com" + File.separator + "libre" + File.separator + "" + str.replace(".", "//") + "" + File.separator + "service");//service
        fileArray[3] = new File(moduleName + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + "com" + File.separator + "libre" + File.separator + "" + str.replace(".", "//") + "" + File.separator + "service" + File.separator + "impl");//serviceImpl
        fileArray[4] = new File(moduleName + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator + "com" + File.separator + "libre" + File.separator + "" + str.replace(".", "//") + "" + File.separator + "controller");//controller
        fileArray[5] = new File(moduleName + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator + "mapper" + File.separator + "" + businessName);//xml
        for (int i = 0; i < fileArray.length; i++) {
            //检查目录是否存在，不存在则创建
            if (!fileArray[i].exists()) {
                fileArray[i].mkdirs();
            }
            //读取模板路径
            Template temp = cfg.getTemplate(fileNameArray[i][0]);
            File docFile = new File(fileArray[i] + File.separator + fileName + fileNameArray[i][1]);
            Writer docout = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
            //输出文件
            temp.process(rootMap, docout);
        }
        System.out.println(" >>>>>> 自动生成代码成功 >>>>>> ");
    }

    //获取数据库表字段名放入map中
    public void getConn(Map<String, Object> rootMap) throws ClassNotFoundException, SQLException {
        Connection conn;
        Class.forName(driver);
        conn = DriverManager.getConnection(url, name, passWord);
        Statement sta = conn.createStatement();
        ResultSet resultSet = sta.executeQuery(sql);
        LinkedHashMap<String, String[]> columnMap = new LinkedHashMap<>();
        LinkedHashMap<String, String> packageMap = new LinkedHashMap<>();
        String[] columnArr = new String[3];
        while (resultSet.next()) {
            String columnName = resultSet.getString(1);
            String columnType = resultSet.getString(2);
            String columnComment = resultSet.getString(3);
            //目前只转换 timestamp，datetime，decimal
            if (columnType.toLowerCase().contains("timestamp")) {
                columnType = "Date";
                packageMap.put(columnType, "import java.util.Date;");
            } else if (columnType.toLowerCase().contains("datetime")) {
                columnType = "Date";
                packageMap.put(columnType, "import java.util.Date;");
            } else if (columnType.toLowerCase().contains("decimal")) {
                columnType = "BigDecimal";
                packageMap.put(columnType, "import java.math.BigDecimal;");
            } else {
                columnType = "String";
            }
            columnArr = new String[]{columnName, columnType, columnComment};
            columnMap.put(columnName, columnArr);
        }
        rootMap.put("columnMap", columnMap);
        rootMap.put("packageMap", packageMap);
        conn.close();
    }

    //将表名转换为类型类名 比如 t_operate_log 转换后为 operateLog ,类名首字母应为大写，这里在freemarker的模板里直接转换
    private String dealTableName() {
        String className = tableName.toLowerCase().substring(tableName.indexOf("_") + 1);
        className = StringUtil.toCamelCase(className);
        return className;
    }

    //将类名转换为文件名，java公共类名与其文件名应该相同，这里将首字母转换为大写 如operateLog 转换后为 OperateLog
    private String dealClassName(String className) {
        String first = className.substring(0, 1).toUpperCase();
        String rest = className.substring(1, className.length());
        String fileName = new StringBuffer(first).append(rest).toString();
        return fileName;
    }

}
